package com.ghostflying.cameraonfly;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import android.os.Handler;
import android.util.Log;

public class ControlNetworkService {
	// private final Handler mHandler;
	private int mState;

	public static final int STATE_NONE = 0; // we're doing nothing
	public static final int STATE_LISTEN = 1; // now listening for incoming
												// connections
	public static final int STATE_CONNECTING = 2; // now initiating an outgoing
													// connection
	public static final int STATE_CONNECTED = 3; // now connected to a remote
													// device
	private static final String TAG = "WLanService";
	private ServerThread mServerThread = null;
	private ConnectThread mConnectThread = null;
	private ConnectedThread mConnectedThread = null;
	private reConnectThread mreConnectThread = null;
	private static final boolean D = true;
	private Handler mhandler = null;
	private static int i =0;

	public ControlNetworkService(Handler handler) {
		mState = STATE_NONE;
		mhandler = handler;
	}

	private synchronized void setState(int state) {
		if (D)
			Log.d(TAG, "setState() " + mState + " -> " + state);
		mState = state;

		// Give the new state to the Handler so the UI Activity can update
	}

	public synchronized int getState() {
		return mState;
	}

	public void StartListen(int port) {
		mServerThread = null;
		mServerThread = new ServerThread(port);
		setState(STATE_LISTEN);
		mServerThread.start();

	}

	public synchronized void Connect(String ipadd, int port) {
		if (D)
			Log.d(TAG, "connect to: " + ipadd + port);
		if (mState == STATE_CONNECTING) {
			if (mConnectThread != null) {
				mConnectThread.cancel();
				mConnectThread = null;
			}
		}

		mConnectThread = new ConnectThread(ipadd, port);
		mConnectThread.start();
		setState(STATE_CONNECTING);

	}

	private synchronized void reConnect(String ipadd, int port) {
		if (D)
			Log.d(TAG, "reconnect to: " + ipadd + port);
		mhandler.obtainMessage(MainActivity.CONTROL_DISCONNECT, -1, -1, null)
				.sendToTarget();
		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}
		if (mreConnectThread != null) {
			return;
		}
		mreConnectThread = new reConnectThread(ipadd, port);
		mreConnectThread.start();
		setState(STATE_NONE);
	}

	private class reConnectThread extends Thread {
		String mip;
		int mport;

		public reConnectThread(String ipadd, int port) {
			mip = ipadd;
			mport = port;
		}

		public void run() {
			Log.i(TAG, "BEGIN mreConncetThread");
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			synchronized (this) {
				mreConnectThread = null;
			}
			Connect(mip, mport);
		}
	}

	public void write(byte[] out) {
		// Create temporary object
		ConnectedThread r;
		// Synchronize a copy of the ConnectedThread
		synchronized (this) {
			if (mState != STATE_CONNECTED)
				return;
			r = mConnectedThread;
		}
		// Perform the write unsynchronized
		r.write(out);
	}

	public void send_debug_info() {
		byte[] buffer = new byte[80];
		buffer[0] = (byte) 0xAA;
		buffer[1] = (byte) 0x55;
		buffer[2] = 1;
		buffer[3] = (byte) 0x08;
		ByteBuffer bb = ByteBuffer.allocate(4);
		ByteBuffer bb2 = ByteBuffer.allocate(2);
		bb.order(ByteOrder.LITTLE_ENDIAN);
		bb2.order(ByteOrder.LITTLE_ENDIAN);
		bb.putInt(i * 1000);
		i++;
		System.arraycopy(bb.array(), 0, buffer, 8, 4);
		bb.clear();
		bb2.putShort((short) ((20 * Math.random() - 10)/180 * Math.PI * 1000));
		System.arraycopy(bb2.array(), 0, buffer, 22, 2);
		bb2.clear();
		bb2.putShort((short) ((20 * Math.random() - 10)/180 * Math.PI * 1000));
		System.arraycopy(bb2.array(), 0, buffer, 24, 2);
		bb2.clear();
		bb2.putShort((short) ((20 * Math.random() - 10)/180 * Math.PI * 1000));
		System.arraycopy(bb2.array(), 0, buffer, 32, 2);
		bb2.clear();
		write(buffer);

	}

	private class ServerThread extends Thread { // 锟教筹拷锟竭筹拷
		int mport;
		ServerSocket mserverSocket = null;
		private Socket msocket = null;

		public ServerThread(int port) {
			mport = port;
		}

		public void run() {
			Log.i(TAG, "BEGIN mServertThread");

			try {
				mserverSocket = new ServerSocket(mport);

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			while (mState != STATE_CONNECTED) {
				try {
					msocket = mserverSocket.accept();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if (msocket != null) {
					if (D)
						Log.d(TAG, "accepted");
					synchronized (this) {
						switch (mState) {
						case STATE_LISTEN:
						case STATE_CONNECTING:
							// Situation normal. Start the connected thread.
							connected(msocket);
							break;
						case STATE_NONE:
						case STATE_CONNECTED:
							// Either not ready or already connected. Terminate
							// new socket.
							try {
								msocket.close();
							} catch (IOException e) {

								Log.e(TAG, "Could not close unwanted socket", e);
							}
							break;
						}
					}
				}
			}
		}

		public void cancel() {
			if (D)
				Log.d(TAG, "cancel " + this);
			try {
				mserverSocket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	public synchronized void connected(Socket socket) {
		// TODO Auto-generated method stub
		if (D)
			Log.e(TAG, "start connected");
		// Cancel the thread that completed the connection
		if (mConnectThread != null) {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		if (mServerThread != null) {
			mServerThread.cancel();
			mServerThread = null;
		}
		mConnectedThread = new ConnectedThread(socket);
		mConnectedThread.start();
		// mHandler.obtainMessage(InstrumentControl.MESSAGE_TOAST, 1, -1,
		// R.string.WLAN_connected).sendToTarget();
		setState(STATE_CONNECTED);
	}

	private class ConnectThread extends Thread { // 锟斤拷锟斤拷锟竭筹拷
		private String mipadd;
		private int mport;
		private Socket mSocket;

		public ConnectThread(String ipadd, int port) {
			mipadd = ipadd;
			mport = port;
		}

		public void run() {
			try {
				mSocket = new Socket(mipadd, mport);
				// mSocket.setSendBufferSize(32*1024);

			} catch (IOException e) {
				try {
					mSocket.close();
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
					reConnect(mipadd, mport);
				}
			}
			synchronized (this) {
				mConnectThread = null;
			}
			if (mSocket != null) {
				connected(mSocket);
			}

		}

		public void cancel() {
			// TODO Auto-generated method stub
			try {
				mSocket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	private class ConnectedThread extends Thread { // 锟斤拷锟斤拷锟斤拷锟斤拷锟竭筹拷
		private Socket mSocket;
		private InputStream mmInStream;
		private OutputStream mmOutStream;

		public ConnectedThread(Socket socket) {
			// TODO Auto-generated constructor stub
			mSocket = socket;
			InputStream tmpIn = null;
			OutputStream tmpOut = null;

			if (mSocket == null) {
				// mHandler.obtainMessage(InstrumentControl.MESSAGE_TOAST, 1,
				// -1, R.string.WLAN_add_error).sendToTarget();
			} else {
				try {
					tmpIn = mSocket.getInputStream(); // 锟斤拷锟斤拷锟斤拷锟斤拷锟�
					tmpOut = mSocket.getOutputStream();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

			mmInStream = tmpIn;
			mmOutStream = tmpOut;

		}

		public void run() {
			Log.i(TAG, "BEGIN mConnectedThread");
			byte[] buffer = new byte[1024];
			int bytes;
			mhandler.obtainMessage(MainActivity.CONNECT_TO_TABLET_SUCC, -1, -1,
					null).sendToTarget();

			while (true) {
				try {
					// mSocket.setSoTimeout(20000);
					bytes = mmInStream.read(buffer);
					
					// mHandler.obtainMessage(InstrumentControl.MESSAGE_READ,
					// bytes, -1, buffer).sendToTarget();
					if (bytes < 0) {
						// reConnect(mSocket.getInetAddress().getHostAddress(),mSocket.getPort());
						break;
					} else {
						byte[] sendbuffer = new byte[bytes];
						System.arraycopy(buffer, 0, sendbuffer, 0, bytes);
						mhandler.obtainMessage(MainActivity.COMMAND_GET, bytes,-1,sendbuffer).sendToTarget();
					}
					

					// String writeMessage=new String(buffer);
					// System.out.println(writeMessage);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					if (e.getMessage() == null
							|| e.getMessage()
									.equals("recvfrom failed: ETIMEDOUT (Connection timed out)")) {
						// reConnect(mSocket.getInetAddress().getHostAddress(),mSocket.getPort());
						// Log.e(TAG, e.getMessage());
					}
					break;
				}
			}
		}

		public void write(byte[] buffer) { // write锟斤拷锟斤拷byte
			try {
				Log.e(TAG, "start write ");
				mmOutStream.write(buffer);
			} catch (Exception e) {
				Log.e(TAG, "Exception during write", e);
				e.printStackTrace();
				reConnect(mSocket.getInetAddress().getHostAddress(),
						mSocket.getPort());
				/*
				 * reConnect(mSocket.getInetAddress().toString(),mSocket.getPort(
				 * ));
				 */
			}
		}

		public void cancel() { // 锟截憋拷socket
			// TODO Auto-generated method stub
			try {
				mSocket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}